package com.sakiko.audiobook.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sakiko.audiobook.account.client.UserAccountFeignClient;
import com.sakiko.audiobook.album.AlbumInfoFeignClient;
import com.sakiko.audiobook.album.TrackInfoFeignClient;
import com.sakiko.audiobook.common.constant.SystemConstant;
import com.sakiko.audiobook.common.execption.SakiException;
import com.sakiko.audiobook.common.rabbit.constant.MqConst;
import com.sakiko.audiobook.common.rabbit.service.RabbitService;
import com.sakiko.audiobook.common.result.Result;
import com.sakiko.audiobook.model.account.AccountDeductVo;
import com.sakiko.audiobook.model.album.AlbumInfo;
import com.sakiko.audiobook.model.album.TrackInfo;
import com.sakiko.audiobook.model.order.OrderDerate;
import com.sakiko.audiobook.model.order.OrderDetail;
import com.sakiko.audiobook.model.order.OrderInfo;
import com.sakiko.audiobook.model.user.VipServiceConfig;
import com.sakiko.audiobook.order.helper.SignHelper;
import com.sakiko.audiobook.order.mapper.OrderDerateMapper;
import com.sakiko.audiobook.order.mapper.OrderDetailMapper;
import com.sakiko.audiobook.order.mapper.OrderInfoMapper;
import com.sakiko.audiobook.order.service.OrderInfoService;
import com.sakiko.audiobook.user.client.UserInfoFeignClient;
import com.sakiko.audiobook.user.client.VipServiceConfigFeignClient;
import com.sakiko.audiobook.vo.order.OrderDerateVo;
import com.sakiko.audiobook.vo.order.OrderDetailVo;
import com.sakiko.audiobook.vo.order.OrderInfoVo;
import com.sakiko.audiobook.vo.order.TradeVo;
import com.sakiko.audiobook.vo.user.UserInfoVo;
import com.sakiko.audiobook.vo.user.UserPaidRecordVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        // 声明字段接收金额数据
        // 原始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        // 折扣金额
        BigDecimal derateAmount = new BigDecimal("0.00");
        // 订单实际金额
        BigDecimal orderAmount = new BigDecimal("0.00");
        // 声明集合来存储订单明细
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        // 声明集合来存储减免明细
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        // 获取用户信息
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
        Assert.notNull(userInfoVoResult, "用户信息结果集不存在");
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        Assert.notNull(userInfoVo, "用户信息不存在");
        // 属性赋值
        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())) {
            // 购买专辑
            // 判断用户是否购买过专辑; user_paid_album; user_id and album_id
            Result<Boolean> booleanResult = userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
            Assert.notNull(booleanResult, "查询用户是否购买专辑失败");
            if (booleanResult.getData()) { // 买过了
                throw new SakiException(810, "用户已经购买过专辑，不要重复购买");
            }
            // 根据专辑 Id获取专辑对象
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
            Assert.notNull(albumInfoResult, "专辑信息结果集不存在");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑信息不存在");
            // 原始金额
            originalAmount = albumInfo.getPrice();
            // 未购买过！判断用户的身份！在判断用户购买的商品是否有折扣
            if (0 == userInfoVo.getIsVip() || (1 == userInfoVo.getIsVip() && userInfoVo.getVipExpireTime().before(new Date()))) {
                // 普通用户; 判断是否有折扣 albumInfo.getDiscount().compareTo(new BigDecimal("-1")) == 1 有折扣
                if (albumInfo.getDiscount().compareTo(new BigDecimal("-1")) > 0) {
                    // 计算折扣的金额
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount())).divide(new BigDecimal("10"), 2, BigDecimal.ROUND_HALF_UP);
                }
            } else {
                // vip用户
                if (albumInfo.getVipDiscount().compareTo(new BigDecimal("-1")) > 0) {
                    // 计算折扣的金额
                    derateAmount = originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount())).divide(new BigDecimal("10"), 2, BigDecimal.ROUND_HALF_UP);
                }
            }
            // 实际金额
            orderAmount = originalAmount.subtract(derateAmount);
            // 订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(originalAmount);
            orderDetailVoList.add(orderDetailVo);
            // 减免明细
            // 判断折扣金额 > 0，再将减免对象添加进集合中
            if (derateAmount.compareTo(new BigDecimal("0.00")) == 1) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("专辑折扣");
                orderDerateVoList.add(orderDerateVo);
            }
        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())) {
            // 购买声音 0 ==> 购买本集
            Integer trackCount = tradeVo.getTrackCount();
            if (trackCount < 0) {
                throw new SakiException(810, "购买声音数量不能小于0");
            }
            // 获取订单明细集合
            Result<List<TrackInfo>> trackInfoListResult = trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(), tradeVo.getTrackCount());
            Assert.notNull(trackInfoListResult, "查询声音结果集不存在");
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            Assert.notNull(trackInfoList, "查询声音对象不存在");
            // 获取到专辑对象
            Long albumId = trackInfoList.get(0).getAlbumId();
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            Assert.notNull(albumInfoResult, "专辑对象结果集不存在");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑对象不存在");
            // 原始金额: 单价 * 数量 : 单价 => album.price
            originalAmount = 0 == trackCount ? albumInfo.getPrice() : albumInfo.getPrice().multiply(new BigDecimal(trackCount));
            // 订单不打折
            orderAmount = originalAmount;
            // orderDetailVoList
            for (TrackInfo info : trackInfoList) {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(info.getId());
                orderDetailVo.setItemName(info.getTrackTitle());
                orderDetailVo.setItemUrl(info.getCoverUrl());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVoList.add(orderDetailVo);
            }
        } else {
            // 购买 vip; vip_service_config
            Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(tradeVo.getItemId());
            Assert.notNull(vipServiceConfigResult, "查询vip服务配置失败");
            VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
            Assert.notNull(vipServiceConfig, "vip服务配置不存在");
            // 原价
            originalAmount = vipServiceConfig.getPrice();
            // 折扣
            derateAmount = originalAmount.subtract(vipServiceConfig.getDiscountPrice());
            // 实际金额
            orderAmount = vipServiceConfig.getDiscountPrice();
            // 订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemId(vipServiceConfig.getId());
            orderDetailVo.setItemPrice(orderAmount);
            orderDetailVoList.add(orderDetailVo);
            // 减免明细
            if (derateAmount.compareTo(new BigDecimal("0.00")) == 1) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("VIP折扣");
                orderDerateVoList.add(orderDerateVo);
            }
        }
        // 声明一个交易编号
        String tradeNo = UUID.randomUUID().toString().replace("-", "");
        orderInfoVo.setTradeNo(tradeNo);
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        orderInfoVo.setTimestamp(SignHelper.getTimestamp());
        // 校验签名属性，防止用户修改订单数据 + 接口安全性！
        String sign = SignHelper.getSign(JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class));
        orderInfoVo.setSign(sign);
        return orderInfoVo;
    }

    @Override
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        // 校验签名
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        // 页面传递的参数 orderInfoVo.payWay是有值的，但是页面提交 (getSign)的时候是没有的
        map.put("payWay", "");
        SignHelper.checkSign(map);
        // 防止重复提交订单
        String orderKey = userId + orderInfoVo.getTradeNo();
        Boolean res = redisTemplate.opsForValue().setIfAbsent(orderKey, 1, 1, TimeUnit.MINUTES);
        if (!res) {
            throw new SakiException(811, "重复提交订单");
        }
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        if (SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())) {
            // 余额支付
            // 1、扣减余额 account微服务
            // 扣减数据、对哪个用户操作
            AccountDeductVo accountDeductVo = new AccountDeductVo();
            accountDeductVo.setOrderNo(orderNo);
            accountDeductVo.setUserId(userId);
            accountDeductVo.setAmount(orderInfoVo.getOrderAmount());
            accountDeductVo.setContent("订单号: " + orderNo);
            // 获取远程调用结果
            Result result = userAccountFeignClient.checkAndDeduct(accountDeductVo);
            if (200 != result.getCode())
                throw new SakiException(result.getCode(), "扣减金额失败");
            // 2、保存订单
            this.saveOrder(orderInfoVo, userId, orderNo);
            // 修改订单状态
            OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
            orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
            orderInfoMapper.updateById(orderInfo);
            // 3、记录用户购买信息
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setUserId(userId);
            userPaidRecordVo.setOrderNo(orderNo);
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            // 找 购买项目的 Id ==> orderInfoVo. OrderDetailVo. ItemId
            List<Long> itemIds = orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList());
            userPaidRecordVo.setItemIdList(itemIds);
            Result userResult = userInfoFeignClient.savePaidRecord(userPaidRecordVo);
            if (200 != result.getCode())
                throw new SakiException(result.getCode(), "保存用户购买记录失败");
        } else {
            // 在线支付
            this.saveOrder(orderInfoVo, userId, orderNo);
            // 发送延迟消息，实现超时取消订单
            rabbitService.sendDealyMessage(MqConst.EXCHANGE_CANCEL_ORDER, MqConst.ROUTING_CANCEL_ORDER, orderNo, MqConst.CANCEL_ORDER_DELAY_TIME);
        }
        return orderNo;
    }

    @Override
    public void cancelOrder(String orderNo) {
        // 利用业务编号字段防止消息重复消费
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        if (orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_PAID)) {
            return;
        }
        // 修改订单状态
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_CANCEL);
        // 取消订单的本质就是修改订单状态
        orderInfoMapper.updateById(orderInfo);
        // 取消订单只是该业务功能的一部分
        // 更多业务...

    }

    @Override
    public OrderInfo getOrderInfoByOrderNo(String orderNo) {
//        return orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>().eq(OrderInfo::getOrderNo, orderNo));
        // 给支付方式赋值
        if (null != orderInfo) {
            // 通过 pay_way字段赋值名称
            orderInfo.setPayWayName(SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay()) ? "余额" : "在线");
        }

        return orderInfo;
    }

    @Override
    public IPage<OrderInfo> findUserPage(Page<OrderInfo> orderInfoPage, String orderStatus, Long userId) {
        // 获取分页 OrderInfo信息，并赋值状态信息
        IPage<OrderInfo> iPage = orderInfoMapper.selectUserPage(orderInfoPage, orderStatus, userId);
        iPage.getRecords().forEach(orderInfo -> {
            orderInfo.setPayWayName(SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfo.getPayWay()) ? "余额" : "在线");
            // 赋值订单状态 0901-未支付 0902-已支付 0903-已取消
            String orderStatusName = SystemConstant.ORDER_STATUS_UNPAID.equals(orderInfo.getOrderStatus()) ? "未支付" :
                    SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus()) ? "已支付" : "已取消";
            orderInfo.setOrderStatusName(orderStatusName);
        });
        return iPage;
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveOrder(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
        // 保存 order_derate; order_detail; order_info
        // order_info
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        orderInfo.setUserId(userId);
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        orderInfoMapper.insert(orderInfo);
        // order_detail
        List<OrderDetailVo> orderDetailVoList = orderInfoVo.getOrderDetailVoList();
        if (!CollectionUtils.isEmpty(orderDetailVoList)) {
            for (OrderDetailVo orderDetailVo : orderDetailVoList) {
                OrderDetail orderDetail = new OrderDetail();
                BeanUtils.copyProperties(orderDetailVo, orderDetail);
                orderDetail.setOrderId(orderInfo.getId());
                orderDetailMapper.insert(orderDetail);
            }
        }
        // order_derate
        List<OrderDerateVo> orderDerateVoList = orderInfoVo.getOrderDerateVoList();
        if (!CollectionUtils.isEmpty(orderDerateVoList)) {
            for (OrderDerateVo orderDerateVo : orderDerateVoList) {
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(orderDerateVo, orderDerate);
                orderDerate.setOrderId(orderInfo.getId());
                orderDerateMapper.insert(orderDerate);
            }
        }

    }
}
